#pragma once
#include <iostream>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include "Socket.h"

class SelectServer
{
    const static uint16_t default_server_port = 8080;
    const static int DEFAULT_MAX_FD = 10;
    const static int NULL_FD = -1;

public:
    static SelectServer *&GetInstance()
    {
        if (_self == nullptr)
        {
            _self = new SelectServer();
        }
        return _self;
    }

    void Run()
    {
        // 数组第一个为listensock套接字
        _fd_arr[0] = _listensock;
        while (true)
        {
            fd_set readfd;
            FD_ZERO(&readfd);
            // FD_SET(_listensock, &readfd);
            std::cout << "runing" << std::endl;
            int now_max_fd = NULL_FD;
            for (int i = 0; i < _max_fd; i++)
            {
                std::cout << i << ":" << _fd_arr[i] << std::endl;
                if (_fd_arr[i] == NULL_FD)
                    continue;
                FD_SET(_fd_arr[i], &readfd);
                if (_fd_arr[i] > now_max_fd)
                {
                    now_max_fd = _fd_arr[i];
                }
            }
            switch (select(now_max_fd + 1, &readfd, nullptr, nullptr, nullptr))
            {
            case 0:
                std::cout << "timeout" << std::endl;
                break;
            case -1:
                std::cerr << "select errno" << std::endl;
                break;
            default:
                HanderEvent(readfd);
                break;
            }
        }
    }

    ~SelectServer()
    {
        delete[] _fd_arr;
        delete _self;
        _fd_arr = nullptr;
        _self = nullptr;
    }

private:
    SelectServer(uint16_t server_port = default_server_port) : _server_port(server_port)
    {
        _listensock = Socket::Sock();
        Socket::Bind(_listensock, _server_port);
        Socket::Listen(_listensock);
        _fd_arr = new int[_max_fd];
        for (int i = 0; i < _max_fd; i++)
        {
            _fd_arr[i] = NULL_FD;
        }
    }
    SelectServer(const SelectServer &i) = delete;
    void HanderEvent(fd_set &readfd)
    {
        for (int i = 0; i < _max_fd; i++)
        {
            if (FD_ISSET(_fd_arr[i], &readfd))
            {
                if (i == 0)
                {
                    ServerAccept();
                }
                else
                {
                    Recvive(i);
                }
            }
        }
    }
    void ServerAccept()
    {
        std::string client_ip;
        uint16_t client_port;
        int client_errno;
        int sock = Socket::Accept(_listensock, &client_ip, &client_port, &client_errno);
        std::cout << "get new link"
                  << " ip:" << client_ip << " port:" << client_port << std::endl;
        // 将与client通信的套接字设置进select
        // 找数组中空闲的fd
        for (int i = 1; i <= _max_fd; i++)
        {
            if (_fd_arr[i] == NULL_FD)
            {
                _fd_arr[i] = sock;
                break;
            }
            if (i == _max_fd)
            {
                std::cout << "select数组已满" << std::endl;
                // 扩容 ....
                // 直接抛弃
                close(sock);
            }
        }
    }
    void Recvive(int index)
    {
        char buffer[1024];
        std::cout << "client fd[" << index << "]:" << _fd_arr[index] << std::endl;
        ssize_t num = recv(_fd_arr[index], buffer, sizeof(buffer) - 1, 0);
        if (num < 0)
        {
            std::cerr << "recv errno" << std::endl;
            int sock = _fd_arr[index];
            // 将数组里的文件描述符清理，让select不再关心
            _fd_arr[index] = NULL_FD;
            close(sock);
        }
        else if (num == 0)
        {
            std::cout << "client close" << std::endl;
            int sock = _fd_arr[index];
            // 将数组里的文件描述符清理，让select不再关心
            _fd_arr[index] = NULL_FD;
            close(sock);
        }
        // 读取成功
        else
        {
            buffer[num] = 0;
            std::cout << "num:" << num << " client:" << buffer << std::endl;
        }
    }

private:
    static SelectServer *_self;
    size_t _max_fd = DEFAULT_MAX_FD;
    int *_fd_arr = nullptr;
    int _listensock;
    uint16_t _server_port;
};
SelectServer *SelectServer::_self = nullptr;